package com.devin.utils;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;

import java.text.SimpleDateFormat;

/**
 * @ClassName: JsonUtils
 * @date: 2021-03-28 17:15
 * @author: Devin
 * @Description:
 */
public class JsonUtils {

    private static ObjectMapper noClassInfoObjectMapper = new ObjectMapper();

    static {
        //序列化的时候序列对象的所有属性
        noClassInfoObjectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);
        //属性为null时去除该属性，与上面互斥，二选一即可
//        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        //反序列化的时候如果多了其他属性,不抛出异常
        noClassInfoObjectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        //如果是空对象的时候,不抛异常
        noClassInfoObjectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

        //取消时间的转化格式,默认是时间戳,可以取消,同时需要设置要表现的时间格式
        noClassInfoObjectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        noClassInfoObjectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

        //json字符串值带反斜杠("\")，默认反序列化会失败
        noClassInfoObjectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);

        //json字符串带注释符，默认反序列化会失败
        noClassInfoObjectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS,true);

        //Json字符串里数字类型值为正无穷、负无穷或NaN时，默认反序列化会失败
        noClassInfoObjectMapper.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);

        //反序列化可解析以"0"为开头的数字
        noClassInfoObjectMapper.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);

        //Json反序列化可以解析单引号包住的属性名称和字符串值
        noClassInfoObjectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

        //反序列Json字符串中包含制控制字符
        noClassInfoObjectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);

        //反序列Json字符串中属性名没有双引号
        noClassInfoObjectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);

        //修改实体类属性域的可见
//        noClassInfoObjectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //序列化是携带类的信息，为的是反序列化返回类对象
//        noClassInfoObjectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
    }

    /**
     * @Description:TODO {json字符串转换为对象} {params:[json, typeReference],  return:T}
     * @Author: Devin @Date:2021-04-12 21:27
     * @param-0	(json)
     * @param-1	(typeReference)
     * @return  T
    */
    public static <T> T readValue(String json,TypeReference<T> typeReference){
        try {
            return noClassInfoObjectMapper.readValue(json, typeReference);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * @Description:TODO {实体类转换为json字符串} {params:[object],  return:java.lang.String}
     * @Author: Devin @Date:2021-04-12 21:26
     * @param-0	(object)
     * @return  java.lang.String
    */
    public static <T> String writeValueAsString(T object) {
        if(object == null){
            return null;
        }
        if(object.getClass() == String.class){
            return (String)object;
        }
        try {
            return noClassInfoObjectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Description:TODO {直接从json字符串中获取value值} {params:[json, key],  return:java.lang.String}
     * @Author: Devin @Date:2021-04-12 22:24
     * @param-0	(json)
     * @param-1	(key)
     * @return  java.lang.String
    */
    public static String getValueFromJsonNode(String json,String key) {
        try {
            return noClassInfoObjectMapper.readTree(json).get(key).asText();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @Description:TODO {静态内部类，实现单例模式} {params:,  return:}
     * @Author: Devin @Date:2021-04-12 22:16
     * @param-0	(null)
     * @return
    */
    private static class GetObjectMapper{
        private static final ObjectMapper objectMapperWithClass = new ObjectMapper();
        static {
            objectMapperWithClass.setSerializationInclusion(JsonInclude.Include.ALWAYS);
            objectMapperWithClass.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            objectMapperWithClass.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
            objectMapperWithClass.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            objectMapperWithClass.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
            objectMapperWithClass.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
            objectMapperWithClass.configure(JsonParser.Feature.ALLOW_COMMENTS,true);
            objectMapperWithClass.configure(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS, true);
            objectMapperWithClass.configure(JsonParser.Feature.ALLOW_NUMERIC_LEADING_ZEROS, true);
            objectMapperWithClass.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            objectMapperWithClass.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
            objectMapperWithClass.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
            //修改实体类属性域的可见
            objectMapperWithClass.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            //序列化是携带类的信息，为的是反序列化返回类对象
            objectMapperWithClass.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
            System.out.println("objectMapperWithClass静态内部类单例模式");
        }
    }

    /**
     * @Description:TODO {获取配置携带实体类信息的ObjectMapper} {params:[],  return:com.fasterxml.jackson.databind.ObjectMapper}
     * @Author: Devin @Date:2021-04-12 22:05
     * @param-0	()
     * @return  com.fasterxml.jackson.databind.ObjectMapper
    */
    public static ObjectMapper getObjectMapperWithClassInfo(){
        return GetObjectMapper.objectMapperWithClass;
    }
}
